;LDIR.Z80 by Trevor Marshall.....Stolen  from SD-50.ASM
; v1.0 7/23/83
;Created to give a library module for many purposes..including cataloging
;Send any fixes to Thousand Oaks Tech RBBS (805) 492 5472
;
FALSE	EQU	0
TRUE	EQU	NOT FALSE
;********************************
;*				*
;*  USER OPTION SPECIFICATIONS 	*
;*				*
;********************************
;
NPL	EQU	4		;# of names per line (max of 3 for 64x16)
;(max	of 4 for 80x24)

; BDOS	equates

CPM	EQU	5
BDOS	EQU	5
FCB	EQU	5CH		;FCB1

RDCHR	EQU	1		;Read char from	console
WRCHR	EQU	2		;Write char to console
CONST	EQU	11		;Check cons stat
RESET	EQU	13		;Reset disk system
SELDSK	EQU	14		;Select	disk
OPEN	EQU	15		;0FFH=not found
CLOSE	EQU	16		;   "	"
SEARCH	EQU	17		;   "	"
NEXT	EQU	18		;   "	"
READ	EQU	20		;not 0 = EOF
WRITE	EQU	21		;not 0 = disk full
MAKE	EQU	22		;0FFH =	directory full
CURDSK	EQU	25		;Get currently logged disk name
SETDMA	EQU	26		;Set current DMA
GALLOC	EQU	27		;Get address of	allocation vector
CURDPB	EQU	31		;Get current disk parameters
CURUSR	EQU	32		;Get currently logged user number (2.x only)
;
START:
	LD	HL,0
	LD	(LBTOTL),HL
	LD	(LMTOTL),HL
;On entry the filenames are in FCB1...make them .LBR
	LD	HL,FCB+9
	LD	(HL),'L'
	INC	HL
	LD	(HL),'B'
	INC	HL
	LD	(HL),'R'
;
	LD	DE,80H	;set def dir bfr
	LD	C,SETDMA
	CALL	CPM
;
	LD	DE,FCB	;Now ask for matching directory entries
	LD	C,SEARCH ;look for the first
	CALL	CPM
	INC	A
	JR	NZ,SOME.THERE
	LD	HL,NOT.FOUND	;else quit
	LD	B,22
	CALL	TYPEIT	
	JP	EXIT
SOME.THERE: ;calculate filename address
	DEC	A	;inced above
	RLC	A	;A*2
	RLC	A
	RLC	A
	RLC	A	;A*16
	RLC	A	;A*32
	ADD	80H	;now pointing at name
	LD	D,0
	LD	E,A	;get it to DE
	INC	DE	;point at the name
;See if it is the 0 extent, if not skip this name
	LD	HL,11	;point at extent
	ADD	HL,DE
	LD	A,(HL)	;get it
	OR	A
	JR	NZ,GET.NEXT
	XOR	A
	LD	(LNCNT),A
	CALL	LBRTST	;Else print the details
;Done one file, now look for more
GET.NEXT: LD	DE,80H	 ;first reset the DMA to 80h
	LD	C,SETDMA
	CALL	CPM
;
	LD	C,NEXT
	LD	DE,FCB
	CALL	BDOS
	INC	A
	JR	NZ,SOME.THERE	;else exit
EXIT:	CALL	LBEXIT	;after printing the summaries
ERROR.EXIT: JP	0
NOT.FOUND: DB	'++ Library not found ++',0dh,0ah

;************** UTILITY SUBROUTINES *************************
;*	Print	HL in decimal with leading zero	suppression
DECPRT:	SUB	A		;Clear leading zero flag
	LD	(LZFLG),A
	LD	DE,-1000	;Print 1000's digit
	CALL	DIGIT
	LD	DE,-100		;Etc.
	CALL	DIGIT
	LD	DE,-10
	CALL	DIGIT
	LD	A,'0'		;Get 1's digit
	ADD	L
	JP	TYPE
DIGIT:	LD	B,'0'		;Start off with	ASCII 0
DIGLP:	PUSH	HL		;Save current remainder
	ADD	HL,DE		;Subtract
	JP	NC,DIGEX	;Quit on overflow
	POP	AF		;Throw away remainder
	INC	B		;Bump digit
	JP	DIGLP		;Loop back
DIGEX:	POP	HL		;Restore pointer
	LD	A,B
	CP	'0'		;Zero digit?
	JP	NZ,DIGNZ	;No, type it
	LD	A,(LZFLG)	;Leading zero?
	OR	A
	LD	A,'0'
	JP	NZ,TYPE		;Print digit
	LD	A,(SUPSPC)	;Get space suppression flag
	OR	A		;See if	printing file totals
	RET	Z		;Yes, don't give leading spaces
	JP	SPACE		;Leading zero...print space
DIGNZ:	LD	(LZFLG),A	;Set leading zero flag so next zero prints
	JP	TYPE		;And print digit
;
;--------------
CRLF:	LD	A,0DH		;Send CR
	CALL	TYPE
	LD	A,0AH		;Send LF
	JP	TYPE		;Exit to caller	from TYPE
;----------
FPAD:	CALL	TYPE		;Print it, fall	into space
SPACE:	LD	A,' '		;Fall through to TYPE
;*	Output character in A to console, and optionally to printer and/or
;*	the output file.
TYPE:	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD	C,2
	LD	E,A
	CALL	CPM
	POP	HL
	POP	DE
	POP	BC
	RET	
;*	Print	a string at HL of length B
TYPEIT:	LD	A,(HL)
	CALL	TYPE
	INC	HL
	DEC	B
	JP	NZ,TYPEIT
	RET	
;*	Print	string terminated with last byte high on console.
PRINT:	LD	A,(DE)
	PUSH	AF
	AND	7FH
	CALL	TYPE
	POP	AF
	OR	A
	RET	M
	INC	DE
	JP	PRINT

;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	SUBROUTINES to read library file directory
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;Compare routine
COMPR:	PUSH	HL		;Save table addr
	LD	E,(HL)		;Load low order
	INC	HL
	LD	D,(HL)		;Load high order
	INC	HL
	LD	C,(HL)
	INC	HL
	LD	B,(HL)
; BC,DE now point to entries to be compared for L characters
COMP:	EX	DE,HL
	LD	E,A		;Get count
CMPLP:	LD	A,(HL)
	AND	7FH
	LD	D,A
	LD	A,(BC)
	AND	7FH
	CP	D
	INC	HL
	INC	BC
	JP	NZ,NOTEQL	;Quit on mismatch
	DEC	E		;Or end	of count
	JP	NZ,CMPLP
NOTEQL:	POP	HL
	RET			;Cond code tells all, Z=match
;
ENTRYL	;Entry here from below, on multiple file looping
	LD	HL,(LCOUNT)
	LD	A,H		;Is this the last file?
	OR	L
	RET	Z	;if so return to mainline code
	DEC	HL		;Dock file count
	LD	(LCOUNT),HL
	PUSH	BC
	LD	HL,(NEXTL)
	LD	A,11
	CALL	COMPR		;Does this entry match next one?
	POP	BC
	JP	NZ,LBRTST	;No, print it
	INC	HL
	INC	HL		;Skip since highest extent comes last in list
	LD	(NEXTL),HL
	JP	ENTRYL		;Loop back for next lowest extent
;
;	Exit Library member printing
;
LBEXIT	LD	HL,(LMTOTL)
	LD	A,H
	OR	L
	RET	Z
	PUSH	HL		;Save Member count
	XOR	A		;Get a zero to...
	LD	(SUPSPC),A	;Suppress leading spaces in totals
	CALL	CRLF
	CALL	CRLF
	LD	DE,CONTM	;Print "There are "
	CALL	PRINT
	POP	HL		;GET TOTAL MEMBER COUNT BACK
	CALL	DECPRT
	LD	DE,MFILES	;PRINT "Members in "
	CALL	PRINT
	LD	HL,(LBTOTL)
	CALL	DECPRT
	LD	DE,LIBR
	CALL	PRINT
;
	LD	DE,LLENMSG
	CALL	PRINT		;Print " with "
	LD	HL,(L2LENLOC)	;GET TOTAL LENGTH OF .LBR (IN SECTORS)   *****
	PUSH	HL
	XOR	A
	LD	(SUPSPC),A	;SUPRESS LEADING SPACES
;Now have the # of sectors in HL..will cahnge it to kBytes
	LD	A,L	;save the old LSByte
	RR	H
	RR	L	;/2
	OR	A
	RR	H
	RR	L	;/4
	OR	A
	RR	H
	RR	L	;/8 now in k
	AND	A,00000111B ;do we have a remainder?
	JR	Z,PUT.IT3
	INC	HL	;Remainder -> INC HL (Also handles < 1k )
PUT.IT3: CALL	DECPRT
	LD	HL,0
	LD	(LLENLOC),HL	;ZERO OLD COUNT                          *****
	LD	(L2LENLOC),HL
	POP	HL
	LD	DE,LLENMSG2
	CALL	PRINT		;Print " sectors total."
	RET	
;
;* Valid library..dump it out
; on entry DE points to FCB+1 (start of the name)
LBRTST:
	PUSH	DE
	LD	HL,MNPL
	LD	A,(LNCNT)
	CP	(HL)
	CALL	NZ,CRLF
	CALL	CRLF
	LD	HL,LFMSEP	;say 'Library file members for:'
	LD	B,31
	CALL	TYPEIT
	POP	HL	;get ptr to start of name
	PUSH	HL	;save it again
	LD	B,8		;File name length
	CALL	TYPEIT
	LD	A,'.'		;Period	after FN
	CALL	TYPE
	LD	B,3		;Display 3 characters of filetype
	CALL	TYPEIT
	CALL	CRLF
	POP	HL	;get name again
;
; Saves the library file name into LBRFCB
; first set the drive #
	LD	A,(FCB)	;from FCB1
	LD	DE,LBRFCB	;TO
	LD	(DE),A
	INC	DE
	LD	B,11		;name+extent
	CALL	MOVE		;DO THE MOVE from (HL) to (DE)
	EX	DE,HL
	LD	B,25		;then zero rest of FCB
CLMFCB	LD	(HL),0
	INC	HL
	DEC	B
	JP	NZ,CLMFCB
	CALL	SETLDMA		;set DMA to lib bffr
	LD	DE,LBRFCB	;POINT TO FILE
	LD	C,OPEN		;GET FUNCTION
	CALL	CPM		;OPEN IT
	LD	C,READ
	LD	DE,LBRFCB
	CALL	CPM
;	CALL	SETFOP
	LD	HL,LBBUF
	LD	A,(HL)
	OR	A
	JP	Z,CKLDIR	;check directory present and type it
BADLBR	LD	HL,NLBRF	;say 'NOT a library file'
	LD	B,25
	CALL	TYPEIT
LMLEXI	CALL	LBCLOSE		;close the file
	PUSH	DE
	PUSH	HL
	LD	HL,MNPL
	LD	A,(LNCNT)
	CP	(HL)
	CALL	NZ,CRLF
	LD	DE,ILFMSG
	CALL	PRINT		;PRINT "This library contains "
	LD	HL,(LLENLOC)
	PUSH	HL
	XOR	A
	LD	(SUPSPC),A	;SUPRESS LEADING SPACES
;Now have the # of sectors in HL..will cahnge it to kBytes
	LD	A,L	;save LSByte
	RR	H
	RR	L	;/2
	OR	A
	RR	H
	RR	L	;/4
	OR	A
	RR	H
	RR	L	;/8 now in k
	AND	A,00000111B ;do we have a remainder?
	JR	Z,PUT.IT2
	INC	HL	;Also handles <1k
PUT.IT2: CALL	DECPRT
	POP	DE
	LD	HL,(L2LENLOC)
	ADD	HL,DE
	LD	(L2LENLOC),HL
	LD	HL,0
	LD	(LLENLOC),HL
	LD	DE,ILFMS2
	CALL	PRINT		;PRINT "kbytes total."
	POP	HL
	POP	DE
	LD	A,0FFH
	LD	(SUPSPC),A	;PUT BACK LEADING SPACES
	JP	ENTRYL

NLBRF	DEFB	'++Not a LIBRARY file.++',13,10
;
;	Close the library file
;
LBCLOSE LD	DE,LBRFCB
	LD	C,CLOSE
	CALL	CPM
	RET	
;
; SETLDMA - Set the Library file DMA adderss
;
SETLDMA LD	DE,LBBUF
	LD	C,SETDMA
	CALL	CPM
	RET	
;
; CKLDIR - check to see if there indeed is a LBR file
;	  directory and barf if not!
;
CKLDIR:	LD	B,11		;len of file name
	LD	A,' '		;space
	INC	HL
CKDLP:	CP	(HL)
	JP	NZ,BADLBR
	DEC	B
	INC	HL
	JP	NZ,CKDLP
;
; The first entry in the LBR directory is indeed blank.
; Now see if the directory size is >0
;
	LD	E,(HL)		;file starting location low
	INC	HL		;must be zero here
	LD	A,(HL)		;file starting location high
	OR	E		;must be zero here also
	JP	NZ,BADLBR
	INC	HL
	LD	E,(HL)		;get library size low
	INC	HL		;point to library size high
	LD	D,(HL)		;get library size high
	LD	A,D
	OR	E		;library must have some size
	JP	Z,BADLBR
	DEC	DE
	EX	DE,HL
	LD	(SLFILE),HL
	LD	HL,(LBTOTL)
	INC	HL
	LD	(LBTOTL),HL
	LD	A,(MNPL)
	LD	(LNCNT),A	;Reset names per line counter
	LD	B,3
	LD	HL,17
	ADD	HL,DE
	LD	A,(MNPL)
	LD	(LNCNT),A	;Reset names per line counter
	JP	LMTEST
LFMLOP	LD	HL,(SLFILE)	;GET
	LD	A,L
	OR	H
	JP	Z,LMLEXI
	DEC	HL
	LD	(SLFILE),HL
	CALL	SETLDMA
	LD	C,READ
	LD	DE,LBRFCB
	CALL	CPM
;	CALL	SETFOP
	LD	B,4		;GET FILE COUNT PER SECTOR
	LD	HL,LBBUF	;GET BUFFER STARTING ADDRESS
LMTEST	LD	A,(HL)		;Get member open flag
	OR	A		;TEST FOR OPEN
	JP	Z,PRMNAM
LMTESA	LD	DE,32		;Member not open get offset
	ADD	HL,DE		;to next and add it in.
	DEC	B		;is buffer empty ?
	JP	NZ,LMTEST	;No so test next entry
	JP	LFMLOP		;Yes get next buffer...
PRMNAM	PUSH	HL		;Print member NAME and SIZE
	PUSH	BC
	LD	HL,LNCNT
	LD	A,(MNPL)
	CP	(HL)
	JP	NZ,PRMNA1
;
 IF NPL <= 3
	LD	A,3		;If printing less than 4 wide
	CP	(HL)
	JP	C,PRMNA1
	LD	A,(LBRFCB)	;.. precede new	line with drive	name
	ADD	'A'-1
	CALL	TYPE
	LD	A,':'		;Tag header with a colon and a space
	CALL	FPAD		;..and exit back to ENTRY
 ENDIF
;
PRMNA1	POP	BC
	POP	HL
	PUSH	HL
	PUSH	BC
	INC	HL
	LD	B,8		;File name length
	CALL	TYPEIT
	LD	A,'.'		;Period	after FN
	CALL	TYPE
	LD	B,3		;Display 3 characters of filetype
	CALL	TYPEIT
	INC	HL
	INC	HL
	LD	E,(HL)
	INC	HL
	LD	D,(HL)
	EX	DE,HL
;If	report size enabled, output the size of the individual file.
	PUSH	DE
	PUSH	HL
	PUSH	HL
	LD	HL,(LLENLOC)
	PUSH	HL
	POP	DE
	POP	HL
	ADD	HL,DE
	LD	(LLENLOC),HL
	POP	HL
	POP	DE
;Now have the # of sectors in HL..will cahnge it to kBytes
	XOR	A
	LD	A,L	;save LSByte
	RR	H
	RR	L	;/2
	OR	A
	RR	H
	RR	L	;/4
	OR	A
	RR	H
	RR	L	;/8 now in k
	AND	A,00000111B ;do we have a remainder?
	JR	Z,PUT.IT ;if not then print it
	INC	HL	;Also handles <1k
PUT.IT:	CALL	DECPRT		;..go print it
	LD	A,'k'		;..and follow with k
	CALL	TYPE
	LD	A,','
	CALL	TYPE
;* At least one more file to output - can we put	it on the current line?
	LD	HL,(LMTOTL)
	INC	HL
	LD	(LMTOTL),HL
	LD	A,(LNCNT)
	DEC	A
	LD	(LNCNT),A
	PUSH	AF
	CALL	NZ,SPACE ;If room left, output the space character
	POP	AF
	POP	BC
	POP	HL
	JP	NZ,LMTESA	;.. and	go output another file
;*Current line full, start a new one.
	LD	A,(MNPL)
	LD	(LNCNT),A	;Reset names per line counter
	CALL	CRLF		;Space down to next line
	JP	LMTESA
;
; Move characters from 'HL' to 'DE' length in 'B'
;
MOVE:	LD	A,(HL)		;GET A CHAR
	LD	(DE),A		;STORE IT
	INC	HL		;TO NEXT "FROM"
	INC	DE		;TO NEXT "TO"
	DEC	B		;MORE?
	JP	NZ,MOVE		;   YES, LOOP
	RET			;   NO, RETURN
;
;
;*	Initialized data area

LFMSEP	db	'    Library file members for : '
LBRTYP	db	'LBR'
CONTM	DEFB	'    There are',' '+80H
MFILES	DEFB	' Member Files in',' '+80H
LIBR	DEFB	' Library(s',')'+80H
LLENMSG DEFB	' totalling',' '+80H
LLENMSG2 DEFB	' kBytes','.'+80H
ILFMSG	DEFB	'    This library contains',' '+80H
ILFMS2	DEFB	' kBytes','.'+80H
;* Uninitialized	data area
LZFLG	DEFS	1		;0 when	printing leading zeros
SUPSPC	DEFS	1		;Leading space flag for	decimal	routine
;
LLENLOC DEFW	0		;RUNNING TOTAL OF LBR LENGTH (SECS)     *****
L2LENLOC DEFW	0		;""
LMTOTL	DEFW	0
LBTOTL	DEFW	0
LNCNT	DEFB	0
LCOUNT	DEFW	0
NEXTL	DEFW	0
SLFILE	DEFW	0
LBRFCB:	DEFS	36
LBBUF	DEFS	80H
MNPL:	DW	NPL	;entries per line
;
	END	
 